/*
  Copyright (C) 2023-2025 ZNYW.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <openssl/aes.h>
#include <limits.h> // 包含PATH_MAX常量
#include <dirent.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>


#if defined(WIN32) || defined(WIN64)
#include "windows.h"
#endif

#include "define.h"
#include "common.h"
#include "zlog.h"
#include "JsonParser.h"

Snowflake sf;
char g_ServerIp[64] = { 0 };
char g_ServerPort[64] = { 0 };
extern sqlite3 *g_sqlite3_db;

// 定义互斥锁
pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER;

void timeSleep(int ms)
{
#if defined(WIN32) || defined(WIN64)
	Sleep(ms);
#else
	usleep(ms * 1000);
#endif
}

/**
 * @description: 查看文件夹是否存在不存在创建
 * @param {char} *path
 * @return {*}
 */
int checkAndCreateDirectory(const char *path)
{
	struct stat st;
	int result = stat(path, &st);
	if (result == 0)
	{
		if (S_ISDIR(st.st_mode))
		{
			// 文件夹已存在
			return 1;
		}
		else
		{
			// 路径已存在但不是文件夹
			return 0;
		}
	}
	else
	{
		// 文件夹不存在，尝试创建文件夹
		result = mkdir(path, 0777); // 设置权限为777，可根据需求进行修改
		if (result == 0)
		{
			// 创建文件夹成功
			return 1;
		}
		else
		{
			// 创建文件夹失败
			int error = errno;
			dzlog_error("create directory error %s", strerror(errno));
			return 0;
		}
	}
}
/**
 * @description: md5文件计算
 * @param {char} *file_path
 * @param {char} *md5_hash
 * @return {*}
 */
void calculate_md5(const char *file_path, char *md5_hash)
{
	FILE *file = fopen(file_path, "rb");
	if (file == NULL)
	{
		dzlog_error("Failed to open file calculate_md5 file_path:%s\n", file_path);
		return;
	}

	MD5_CTX md5_context;
	MD5_Init(&md5_context);

	unsigned char buffer[1024];
	int bytes;

	while ((bytes = fread(buffer, 1, sizeof(buffer), file)) != 0)
	{
		MD5_Update(&md5_context, buffer, bytes);
	}

	unsigned char tmp[100];

	MD5_Final(tmp, &md5_context);
	int i = 0;
	for (i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf(md5_hash + (i * 2), "%02x", tmp[i]);
	}
	md5_hash[MD5_DIGEST_LENGTH * 2] = '\0';
	fclose(file);
}

/**
 * @description: 文件sha256
 * @param {char} *filename
 * @param {unsigned char} *hash
 * @return {*}
 */
void calculate_file_sha256(const char *filename, char *hash_hex)
{
	FILE *file;
	SHA256_CTX sha256_ctx;
	unsigned char buffer[BUFFER_SIZE];
	size_t bytes_read;

	// 打开文件以进行读取操作
	file = fopen(filename, "rb");
	if (file == NULL)
	{
		printf("Failed to open the file.\n");
		return;
	}

	// 初始化 SHA-256 上下文
	if (!SHA256_Init(&sha256_ctx))
	{
		printf("Failed to initialize SHA-256 context.\n");
		fclose(file);
		return;
	}

	// 逐步读取文件内容并更新 SHA-256 哈希值
	while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) > 0)
	{
		if (!SHA256_Update(&sha256_ctx, buffer, bytes_read))
		{
			printf("Failed to update SHA-256 context.\n");
			fclose(file);
			return;
		}
	}

	// 完成哈希计算并获取最终的 SHA-256 哈希值
	unsigned char hash[SHA256_DIGEST_LENGTH];
	if (!SHA256_Final(hash, &sha256_ctx))
	{
		printf("Failed to finalize SHA-256 context.\n");
		fclose(file);
		return;
	}

	// 关闭文件
	fclose(file);

	// 将哈希值转换为十六进制字符串
	int i = 0;
	i = 0;
	while (i < SHA256_DIGEST_LENGTH)
	{
		sprintf(&hash_hex[i * 2], "%02x", hash[i]);
		i++;
	}
}

/**
 * @description: 文件大小计算
 * @param {char} *file_path
 * @return {*}
 */
long calculate_file_size(const char *file_path)
{
	FILE *file = fopen(file_path, "rb");
	if (file == NULL)
	{
		dzlog_error("Failed to open file.file_path:%s\n", file_path);
		return -1; // 返回错误代码
	}

	fseek(file, 0, SEEK_END);	  // 将文件指针定位到文件末尾
	long file_size = ftell(file); // 获取文件指针的当前位置，即文件大小

	fclose(file);
	return file_size;
}

unsigned int getstimeval()
{
	unsigned int us;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	us = (int)(tv.tv_usec);
	return us;
}

void GF_GetGUID(char* uuid) {
	// 16 字节的 UUID 数据
	unsigned char data[16];

	// 使用当前时间初始化随机种子
	srand((unsigned int)time(NULL) + rand());

	// 生成 16 个随机字节
	for (int i = 0; i < 16; ++i) {
		data[i] = (unsigned char)(rand() % 256);
	}

	// 设置版本：第 7 字节高 4 位为 0100 (0x40)
	data[6] = (data[6] & 0x0F) | 0x40;

	// 设置变体：第 9 字节高 2 位为 10 (0x80)
	data[8] = (data[8] & 0x3F) | 0x80;

	// 格式化为 UUID 字符串 (8-4-4-4-12)
	snprintf(uuid, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
		data[0], data[1], data[2], data[3],
		data[4], data[5],
		data[6], data[7],
		data[8], data[9],
		data[10], data[11], data[12], data[13], data[14], data[15]);

	return;
}

#define AES_BITS 128

static unsigned char char_to_i(char ch)
{
	unsigned char byte = 0;
	if (ch >= 'A' && ch <= 'F')
	{
		byte = 10 + (ch - 'A');
	}
	else if (ch >= 'a' && ch <= 'f')
	{
		byte = 10 + (ch - 'a');
	}
	else
		byte = ch - '0';

	return byte;
}

static unsigned char hex_to_byte(char b1, char b2)
{
	unsigned char byte1 = char_to_i(b1);
	unsigned char byte2 = char_to_i(b2);

	return (byte1 * 16 + byte2);
}

char *string_to_hex(const char *str, int *outlen)
{
	int len = strlen(str);
	if ((len % 2) != 0)
	{
		dzlog_error("cmd:[SYSTEM], msg:[string_to_hex, string length not  2*N ");
		return NULL;
	}

	int bytelen = len / 2;
	char *out = malloc(bytelen);
	int i = 0, offset = 0;
	while (i < len)
	{
		char ch1 = str[i];
		char ch2 = str[i + 1];
		out[offset] = hex_to_byte(ch1, ch2);
		i += 2;
		offset++;
	}

	(*outlen) = bytelen;
	return out;
}

/**
 * @brief 查询字典表
 *
 * @param key 查询key
 * @param value 传入字符串数组
 * @param parentid 查询父节点
 * @return int 成功返回1失败返回0
 */
int sql_dict(const char *key, char *value, const char parentid)
{
	char *sql[1024] = {0};
	char *err_msg = NULL;

	sprintf(sql, "select value from dict_item where key = %s and parentid = %s", key, parentid);
	if (sqlite3_exec(g_sqlite3_db, sql, dict_callback, value, &err_msg) != SQLITE_OK)
	{
		dzlog_error("查询失败，查找不到key = %s,parentid = %s,error=%s", key, parentid, sqlite3_errmsg(g_sqlite3_db));
		sqlite3_free(err_msg);
		return 0;
	}
	return 1;
}

/// @brief 非递归查找文件第一个匹配文件名
/// @param directory
/// @param keyword
/// @return
char *search_directory_firstone(const char *directory, const char *keyword)
{
	DIR *dir = opendir(directory);
	if (dir == NULL)
	{
		dzlog_error(stderr, "无法打开目录 %s\n", directory);
		return NULL;
	}

	char *match = NULL;

	struct dirent *entry;
	while ((entry = readdir(dir)) != NULL)
	{
		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
		{
			continue;
		}

		char path[PATH_MAX];
		snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);

		struct stat statbuf;
		if (stat(path, &statbuf) == -1)
		{
			continue;
		}

		if (S_ISREG(statbuf.st_mode))
		{
			if (strstr(entry->d_name, keyword) != NULL)
			{
				match = realpath(path, NULL);
				break;
			}
		}
	}

	closedir(dir);

	return match;
}

/**
 * @brief Get the absolute path object
 * 获取文件绝对路径
 * @param relative_path
 * @return char*
 */
char *get_absolute_path(const char *relative_path)
{
	char *absolute_path = realpath(relative_path, NULL);
	return absolute_path;
}

int dict_callback(void *data, int argc, char **argv, char **azColName)
{
	char *result = (char *)data;
	int i = 0;
	while (i < argc)
	{
		if (strcmp(azColName[i], "value") == 0)
		{
			sprintf(result, "%s\0", argv[i]);
		}
		i++;
	}
	return 0;
}

void get_os_name(char *osName)
{
	char result[1024] = {0};
	FILE *fp;
	fp = popen("cat /etc/os-release | grep NAME | grep -v PRETTY_NAME | grep -v DISTRO_CODENAME", "r");
	if (fp == NULL)
	{
		dzlog_error("get_os_name cmd exec error");
		return;
	}
	if (fgets(result, 100, fp) != NULL)
	{
		strcpy(osName, result);
		dzlog_info("get_os_name[%s]", osName);
	}
	pclose(fp);
}

void free_s(void *ptr)
{
	if (ptr != NULL)
	{
		free(ptr);
		ptr = NULL;
	}
}

int get_file_json(char *content, const char *filename)
{
	FILE *file = NULL;
	char *buffer = NULL;
	long file_size = 0;
	struct stat buffertemp;
	if (stat(filename, &buffertemp) == 0)
	{
		// 打开文件
		file = fopen(filename, "rb");
		if (file == NULL)
		{
			printf("无法打开文件 conf/%s\n", filename);
			return -1;
		}
		// 获取文件大小
		fseek(file, 0, SEEK_END);
		file_size = ftell(file);
		rewind(file);

		// 分配内存以存储文件内容
		buffer = (char *)malloc(sizeof(char) * (file_size + 1));
		if (buffer == NULL)
		{
			printf("内存分配失败");
			fclose(file);
			return -2;
		}

		// 读取文件内容到缓冲区
		fread(buffer, 1, file_size, file);
		buffer[file_size] = '\0';

		strcpy(content, buffer);

		// 释放内存并关闭文件
		free(buffer);
		fclose(file);
		return 0;
	}
	else
	{
		return -3;
	}
}

int toGetMemUsed(int pid, char *res)
{
	char cmd[64] = {0};
	int isreturn = -1;
	FILE *fp = NULL;
	char buffer[128];
	char buf[255];
	int i = 0;

	long Tmem = 0;
	long umem = 0;
	if ((fp = popen("cat /proc/meminfo | grep MemTotal", "r")) == NULL)
	{
		dzlog_info("toGetMemUsed start 22");
		pclose(fp);
		return -1;
	}
	// 读取输出行
	while (fgets(buffer, sizeof(buffer), fp) != NULL)
	{
		// 使用 sscanf 截取数字
		if (sscanf(buffer, "MemTotal: %ld kB", &Tmem) == 1)
		{
			break;
		}
	}
	pclose(fp);
	char dir[128] = {0};
	sprintf(dir, "/proc/%d/stat", pid);
	struct stat st = {0};
	if (stat(dir, &st) == -1)
	{
		// dzlog_info("toGetMemUsed start 55 dir[%s] not found", dir);
		return -1;
	}
	memset(cmd, 0, 64);
	sprintf(cmd, "cat /proc/%d/status | grep VmRSS", pid);
	if ((fp = popen(cmd, "r")) == NULL)
	{
		dzlog_info("toGetMemUsed start 88 cmd[%s]", cmd);
		pclose(fp);
		return -1;
	}
	// 读取输出行
	while (fgets(buffer, sizeof(buffer), fp) != NULL)
	{
		// 使用 sscanf 截取数字   VmRSS:      2912 kB
		if (sscanf(buffer, "VmRSS: %ld kB", &umem) == 1)
		{
			break;
		}
	}
	pclose(fp);
	sprintf(res, "%.2f", (double)umem / (double)Tmem * 100);


	return 0;
}

int toGetCpuUsed(int pid, char *res)
{
	char cmd[64] = {0};
	int isreturn = -1;
	FILE *fp = NULL;
	char buf[256];
	int i = 0;

	char stat_path[32];
	char buffer[1024];
	unsigned long utime, stime;
	long hertz = sysconf(_SC_CLK_TCK);

	// 读取第一次数据
	sprintf(stat_path, "/proc/%d/stat", pid);
	fp = fopen(stat_path, "r");
	if (!fp)
		return -1;

	fgets(buffer, sizeof(buffer), fp);
	sscanf(buffer, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu", &utime, &stime);
	unsigned long total_time1 = utime + stime;
	fclose(fp);

	// 睡眠一段时间
	sleep(1);

	// 读取第二次数据
	fp = fopen(stat_path, "r");
	if (!fp)
		return -1;

	fgets(buffer, sizeof(buffer), fp);
	sscanf(buffer, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu", &utime, &stime);
	unsigned long total_time2 = utime + stime;
	fclose(fp);

	// 计算CPU使用率
	double cpu_usage = ((total_time2 - total_time1) * 100.0) / (hertz * 0.5);
	sprintf(res, "%.2f", cpu_usage);


	return 0;
}

void remove_newlines(char *str) {
    if (!str) return;
    
    char *src = str;  // 源指针（读取位置）
    char *dst = str;  // 目标指针（写入位置）

    while (*src) {
        if (*src != '\r' && *src != '\n') {
            *dst++ = *src;  // 保留非换行字符
        }
        src++;
    }
    *dst = '\0';  // 添加字符串结束符
}

void remove_spaces(char *str)
{
	int i, j = 0;
	int len = strlen(str);
	for (i = 0; i < len; i++)
	{
		if (str[i] != ' ')
		{
			str[j++] = str[i];
		}
	}
	str[j] = '\0';
}

int setstatus(int status)
{
	// 没有文件，创建文件并写入
	FILE* file1 = fopen("/PowerHarmony/SMC/app/EagleEyeSMG/conf/status", "w");
	if (file1 == NULL)
	{
		return -1;
	}
	// 写入内容
	fprintf(file1, "%d", status);
	// 关闭文件
	fclose(file1);

	return 0;
}

void modify_ip(char *ip, int netmask)
{
	int octets[4];
	sscanf(ip, "%d.%d.%d.%d", &octets[0], &octets[1], &octets[2], &octets[3]);
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		if (netmask < (i + 1) * 8)
		{
			octets[i] = 0;
		}
	}

	sprintf(ip, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
}

void tosetroute()
{
	char ip_tmp[16] = {0};
	char port[16] = {0};
	char ip_route_json[16] = {0};
	char netmask[16] = {0};
	char gw[16] = {0};

	// 读取route.json
	char routePath[255] = "/PowerHarmony/SMC/Config/route.json";
	char pcJson1[255] = {0};
	memset(pcJson1, 0, 255);
	int rei = get_file_json(pcJson1, routePath);
	if (rei < 0)
	{
		return rei;
	}
	cJSON *json0 = NULL;
	json0 = cJSON_Parse(pcJson1);
	if (json0)
	{
		if (cJSON_HasObjectItem(json0, "port"))
		{
			strcpy(port, cJSON_GetObjectItem(json0, "port")->valuestring);
		}
		if (cJSON_HasObjectItem(json0, "ipAddress"))
		{
			strcpy(ip_route_json, cJSON_GetObjectItem(json0, "ipAddress")->valuestring);
		}
		if (cJSON_HasObjectItem(json0, "prefixLen"))
		{
			strcpy(netmask, cJSON_GetObjectItem(json0, "prefixLen")->valuestring);
		}
		if (cJSON_HasObjectItem(json0, "gateway"))
		{
			strcpy(gw, cJSON_GetObjectItem(json0, "gateway")->valuestring);
		}
	}
	cJSON_Delete(json0);
	if (strlen(port) == 0)
	{
		strcpy(port, "ppp0");
	}
	modify_ip(ip_route_json, atoi(netmask));
	if (netmask != NULL && strlen(netmask) != 0)
	{
		if (atoi(netmask) <= 8)
		{
			sprintf(netmask, "8");
		}
		else if (atoi(netmask) > 8 && atoi(netmask) <= 16)
		{
			sprintf(netmask, "16");
		}
		else if (atoi(netmask) > 16 && atoi(netmask) <= 24)
		{
			sprintf(netmask, "24");
		}
		else
		{
			sprintf(netmask, "32");
		}
	}
	char setroute[255] = {0};
	
	if (ip_route_json != NULL || strlen(ip_route_json) != 0)
	{
		memset(setroute, 0, 255);
		if (gw != NULL || strlen(gw) != 0)
		{
			sprintf(setroute, "ip route add %s/%s via %s dev %s", ip_route_json, netmask, gw, port);
		}
		else
		{
			sprintf(setroute, "ip route add %s/%s dev %s", ip_route_json, netmask, port);
		}

		strcat(setroute, " > /dev/null 2> error.log");
		// printf(setroute);
		// printf("\n");
		system(setroute);
	}
	printf("1");
	return;
}

void togettime_ym(char *date_ym)
{
	time_t current_time = time(NULL);
	if (current_time == -1)
	{
		perror("Failed to get current time");
		return 1;
	}

	struct tm *time_info = localtime(&current_time);
	if (time_info == NULL)
	{
		perror("Failed to convert time");
		return 1;
	}

	int year = time_info->tm_year + 1900;
	int month = time_info->tm_mon + 1;

	sprintf(date_ym, "%04d%02d", year, month);
	return;
}

int popen_get_json(char **json_string, const char *cmd)
{
	char buf[256] = {0};
	FILE *fp = NULL;
	size_t len = 0;
	*json_string = NULL; // 初始化为NULL，以便在需要时分配内存

	if ((fp = popen(cmd, "r")) == NULL)
	{
		perror("popen");
		return -1;
	}
	// 初始分配内存
	*json_string = malloc(1);
	if (*json_string == NULL)
	{
		perror("malloc");
		pclose(fp);
		return -1;
	}
	**json_string = '\0'; // 初始化为空字符串
						  // 读取result到内存中
	while (fgets(buf, sizeof(buf), fp) != NULL)
	{
		// 为新的字符串内容分配内存（包括之前的内容和新的行）
		char *temp = realloc(*json_string, len + strlen(buf) + 1);
		if (temp == NULL)
		{
			perror("realloc");
			pclose(fp);
			free(*json_string); // 释放之前分配的内存
			*json_string == NULL;
			return -1;
		}
		*json_string = temp;
		strcat(*json_string, buf);
		len += strlen(buf);
	}
	// 去掉可能的换行符（如果 JSON 文件不是单行的话）
	if (len > 0 && (*json_string)[len - 1] == '\n')
	{
		(*json_string)[len - 1] = '\0';
	}
	// dzlog_info("%s:%s",cmd,*json_string);
	pclose(fp);

	return 0;
}

void generate_random_string(char *str, size_t length) { 
    const char charset[] = "0123456789"
                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                           "abcdefghijklmnopqrstuvwxyz";
    
    // // 设置随机种子
    // srand(time(NULL));

    for (size_t i = 0; i < length-1; i++) {
        int index = rand() % (sizeof(charset) - 1);
        str[i] = charset[index];
    }
    str[length-1] = '\0'; // 字符串结尾
}

/**
 * @brief 判断字符串是否纯ASCII，若否则转换非ASCII字符
 * @param input   输入字符串
 * @param mode    转换模式：0-移除非ASCII，1-替换为'?'，2-转义为\xHH
 * @return char*  转换后的字符串（需调用者释放内存）
 */
void convert_to_ascii(const char* input, char* output, int mode)
{
	if (!input)
		return NULL;

	// 计算输出字符串最大可能长度
	size_t in_len = strlen(input);
	size_t out_len = (mode == 2) ? in_len * 4 : in_len + 1;
	//char* output = malloc(out_len);
	if (!output)
		return NULL;

	size_t j = 0;
	for (size_t i = 0; i < in_len; ++i)
	{
		unsigned char c = input[i];
		if (c <= 127)
		{ // ASCII字符直接保留
			output[j++] = c;
		}
		else
		{ // 非ASCII字符处理
			switch (mode)
			{
			case 0: // 模式0：直接移除
				break;
			case 1: // 模式1：替换为'?'
				output[j++] = '?';
				break;
			case 2: // 模式2：转义为\xHH形式（如\xA3）
				snprintf(output + j, 4, "\\x%02X", c);
				j += 4;
				break;
			default: // 无效模式视为模式0
				break;
			}
		}
	}
	output[j] = '\0'; // 终止符

	//// 优化内存：按实际长度重新分配
	//char* final = realloc(output, j + 1);
	//return final ? final : output;
	return;
}

int split_string(char* input, char tmp[4][6]) {
	char* token;
	int i = 0;
	token = strtok(input, "|");
	while (token != NULL && i < 4) {
		if (token != NULL && strlen(token) != 0)
		{
			dzlog_info("i[%d],token[%s]",i, token);
			strncpy(tmp[i], token, 5);
			tmp[i][5] = '\0';
			i++;
		}
		token = strtok(NULL, "|");
	}
	return i;
}

void move_matched_connection_to_front(cJSON* root, const char* target_ip) {

	cJSON* connections = cJSON_GetObjectItemCaseSensitive(root, "connections");
	if (!connections || !cJSON_IsArray(connections)) return;
	cJSON* matched = NULL;
	cJSON* item = NULL;

	// 查找匹配的IP
	cJSON_ArrayForEach(item, connections) {
		cJSON* ip = cJSON_GetObjectItem(item, "ip");
		if (ip && cJSON_IsString(ip) && strcmp(ip->valuestring, target_ip) == 0) {
			matched = item;
			break;
		}
	}
	if (matched) {
		// 创建新数组并调整顺序
		cJSON* new_array = cJSON_CreateArray();
		cJSON_AddItemToArray(new_array, cJSON_Duplicate(matched, 1));  // 复制匹配项到首位

		// 添加其他元素（跳过匹配项）
		cJSON_ArrayForEach(item, connections) {
			if (item != matched) {
				cJSON_AddItemToArray(new_array, cJSON_Duplicate(item, 1));
			}
		}

		// 直接替换根对象中的connections数组
		cJSON_ReplaceItemInObject(root, "connections", new_array);
	}
}

//雪花算法//////
// 获取当前毫秒时间戳
uint64_t current_timestamp() {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000;
}

// 初始化雪花算法结构
int snowflake_init(Snowflake* sf, uint64_t worker_id) {
	if (worker_id > MAX_WORKER_ID) {
		return -1;  // 无效的worker_id
	}

	sf->last_timestamp = 0;
	sf->worker_id = worker_id;
	sf->sequence = 0;
	pthread_mutex_init(&sf->mutex, NULL);
	return 0;
}

// 生成唯一ID
uint64_t snowflake_next_id(Snowflake* sf) {
	pthread_mutex_lock(&sf->mutex);

	uint64_t timestamp = current_timestamp();

	// 处理时钟回拨
	if (timestamp < sf->last_timestamp) {
		// 简单处理：等待时钟追上
		while (timestamp < sf->last_timestamp) {
			usleep(1000);  // 休眠1毫秒
			timestamp = current_timestamp();
		}
	}

	// 同一毫秒内的序列处理
	if (timestamp == sf->last_timestamp) {
		sf->sequence = (sf->sequence + 1) & MAX_SEQUENCE;
		if (sf->sequence == 0) {
			// 当前毫秒序列号用完，等待下一毫秒
			while (timestamp <= sf->last_timestamp) {
				usleep(1000);
				timestamp = current_timestamp();
			}
		}
	}
	else {
		sf->sequence = 0;  // 新毫秒重置序列
	}

	sf->last_timestamp = timestamp;

	// 组合ID
	uint64_t id = ((timestamp - EPOCH) << (WORKER_ID_BITS + SEQUENCE_BITS))
		| (sf->worker_id << SEQUENCE_BITS)
		| sf->sequence;

	pthread_mutex_unlock(&sf->mutex);
	return id;
}

// 清理资源
void snowflake_cleanup(Snowflake* sf) 
{
	pthread_mutex_destroy(&sf->mutex); 
}

uint64_t getSnowflakeId(char * output_id)
{
	uint64_t id = snowflake_next_id(&sf);
	printf("Generated ID: %lu\n", id);
	snprintf(output_id, 37, "%lu", id);
	//snowflake_cleanup(&sf);
	return id;
}

//雪花算法end//////////////

double convert_string_to_double(const char* input) {
	// 步骤1: 创建可修改的字符串副本
	char* buffer = strdup(input);
	if (!buffer) {
		perror("内存分配失败");
		return 0.0;
	}

	// 步骤2: 去除所有百分号
	char* read_ptr = buffer;
	char* write_ptr = buffer;

	while (*read_ptr) {
		if (*read_ptr != '%') {
			*write_ptr = *read_ptr;
			write_ptr++;
		}
		read_ptr++;
	}
	*write_ptr = '\0';  // 添加字符串终止符

	// 步骤3: 去除前后空格
	// 跳过前导空格
	char* start = buffer;
	while (isspace((unsigned char)*start)) start++;

	// 处理后置空格
	char* end = start + strlen(start) - 1;
	while (end > start && isspace((unsigned char)*end)) end--;
	*(end + 1) = '\0';

	// 步骤4: 转换为double
	char* endptr;
	double result = strtod(start, &endptr);

	// 步骤5: 检查转换是否成功
	if (endptr == start) {
		fprintf(stderr, "错误: 无法转换字符串 '%s'\n", input);
		result = 0.0;  // 或者返回错误代码
	}
	else if (*endptr != '\0') {
		fprintf(stderr, "警告: 字符串 '%s' 包含额外字符 '%s'\n", input, endptr);
	}

	// 清理内存
	free(buffer);
	return result;
}

/**
 * 检测指定IP和端口的网络连通性
 *
 * @param ip 目标IP地址 (字符串格式，如 "192.168.1.100")
 * @param port 目标端口号
 * @param timeout_sec 超时时间(秒)
 *
 * @return 连接成功返回0，失败返回错误代码:
 *   -1: 参数错误
 *   -2: 创建socket失败
 *   -3: 设置非阻塞失败
 *   -4: 连接失败
 *   -5: 连接超时
 *   -6: 其他错误
 */
int check_connectivity(const char* ip, int port, int timeout_sec) {
	// 参数校验
	if (!ip || port <= 0 || port > 65535 || timeout_sec <= 0) {
		return -1;
	}

	// 创建TCP socket
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		return -2;
	}

	// 设置非阻塞模式
	int flags = fcntl(sock, F_GETFL, 0);
	if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
		close(sock);
		return -3;
	}

	// 设置目标地址
	struct sockaddr_in addr = {
		.sin_family = AF_INET,
		.sin_port = htons(port)
	};

	// 转换IP地址
	if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
		close(sock);
		return -1; // 无效的IP地址
	}

	// 发起非阻塞连接
	int rc = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
	if (rc == 0) {
		// 立即连接成功（本地连接可能）
		close(sock);
		return 0;
	}

	// 检查错误类型
	if (errno != EINPROGRESS) {
		close(sock);
		return -4;
	}

	// 使用select等待连接完成
	fd_set writefds;
	FD_ZERO(&writefds);
	FD_SET(sock, &writefds);

	struct timeval timeout = {
		.tv_sec = timeout_sec,
		.tv_usec = 0
	};

	rc = select(sock + 1, NULL, &writefds, NULL, &timeout);
	if (rc == 0) {
		// 超时
		close(sock);
		return -5;
	}
	else if (rc < 0) {
		// select错误
		close(sock);
		return -6;
	}

	// 检查socket是否真的连接成功
	int error = 0;
	socklen_t len = sizeof(error);
	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
		close(sock);
		return -6;
	}

	close(sock);
	return (error == 0) ? 0 : -4;
}

// 检查文件是否存在
int file_exists_v1(const char* filename) {
	struct stat buffer;
	return (stat(filename, &buffer) == 0);
}

// 获取文件修改时间
time_t get_file_mod_time(const char* filename) {
	struct stat attr;
	if (stat(filename, &attr) == 0) {
		return attr.st_mtime;
	}
	return -1;
}

int set_iot_info_v1(int iotTlsCurrent)
{
	cJSON* json = NULL;
	char* fileName = "./conf/iotInfo.json";
	char tmp[8] = { 0 };
	sprintf(tmp, "%d", iotTlsCurrent);
	struct stat buffer;
	if (!stat(fileName, &buffer) == 0) 
	{
		printf("文件不存在: %s\n", fileName);
		json = cJSON_CreateObject();
		cJSON_AddStringToObject(json, "iotTlsCurrent", tmp);
	}
	else
	{
		char pcJson[512] = { 0 };
		int re = get_file_json(pcJson, fileName);
		cJSON* json1 = NULL;
		json = cJSON_Parse(pcJson);
		if (json)
		{
			if (cJSON_HasObjectItem(json, "iotTlsCurrent"))
			{
				cJSON_ReplaceItemInObject(json, "iotTlsCurrent", cJSON_CreateString(tmp));
			}
			else
			{
				cJSON_AddStringToObject(json, "iotTlsCurrent", tmp);
			}
		}
	}
	dzlog_error("set_iot_info_v1 iotTlsCurrent[%d]", iotTlsCurrent);
	// 将修改后的JSON写回文件
	char* output = cJSON_Print(json);
	FILE* file = fopen(fileName, "w");
	if (file == NULL)
	{
		cJSON_Delete(json);
		free(output);
		printf("0");
		return -1;
	}
	fwrite(output, 1, strlen(output), file);

	fclose(file);
	cJSON_Delete(json);
	free(output);
	system("chmod 777 ./conf/iotInfo.json");
	return 0;
}

int tar_czf_exec(const char* app_path,const char* file_id,const char* filename)
{
	size_t need = strlen(app_path) + strlen(file_id) + 2;
	char work[need];
	snprintf(work, need, "%s/%s", app_path, file_id);

	pid_t pid = fork();
	if (pid == 0) {                                    /* 子进程 */
		if (chdir(work) == -1) { perror("chdir"); _exit(127); }

		char* argv[] = { "tar", "-zxvf", (char*)filename, NULL };
		execve("/bin/tar", argv, (char* []) { "PATH=/bin:/usr/bin", NULL });
		perror("execve");                              /* 失败才到 */
		_exit(126);
	}

	int st;
	if (waitpid(pid, &st, 0) == -1) return -1;
	return WIFEXITED(st) && WEXITSTATUS(st) == 0 ? 0 : -1;
}

int chmod_exec(const char* app_path, const char* filename)
{
	size_t need = strlen(app_path) + 2;
	char work[need];
	snprintf(work, need, "%s", app_path);

	pid_t pid = fork();
	if (pid == 0) {                                    /* 子进程 */
		if (chdir(work) == -1) { perror("chdir"); _exit(127); }

		char* argv[] = { "chmod", "777", (char*)filename, NULL };
		execve("/bin/chmod", argv, (char* []) { "PATH=/bin:/usr/bin", NULL });
		perror("execve");                              /* 失败才到 */
		_exit(126);
	}

	int st;
	if (waitpid(pid, &st, 0) == -1) return -1;
	return WIFEXITED(st) && WEXITSTATUS(st) == 0 ? 0 : -1;
}

int run_sh_script_background(const char* app_path, const char* script_name, const char* arg)
{
	size_t need = strlen(app_path) + 1;
	char dir_path[need];
	snprintf(dir_path, need, "%s", app_path);

	pid_t pid = fork();
	if (pid == 0) {                                    /* 子进程（后台进程的父进程） */
		// 孙进程（真正的后台进程）
		pid_t grandchild = fork();
		if (grandchild == 0) {                         /* 孙进程 */
			// 检查目录是否存在
			struct stat st;
			if (stat(dir_path, &st) == -1) {
				perror("stat");
				_exit(127);
			}

			if (!S_ISDIR(st.st_mode)) {
				fprintf(stderr, "'%s' is not a directory\n", dir_path);
				_exit(127);
			}

			// 切换到目录
			if (chdir(dir_path) == -1) {
				perror("chdir");
				_exit(127);
			}

			// 检查脚本文件是否存在
			if (stat(script_name, &st) == -1) {
				perror("stat");
				_exit(127);
			}

			// 构建 sh 参数数组，包含脚本参数
			if (arg != NULL && arg[0] != '\0') {
				char* argv[] = { "sh", (char*)script_name, (char*)arg, NULL };
				execve("/bin/sh", argv, (char* []) { "PATH=/bin:/usr/bin", NULL });
			}
			else {
				// 如果没有参数，只传递脚本名
				char* argv[] = { "sh", (char*)script_name, NULL };
				execve("/bin/sh", argv, (char* []) { "PATH=/bin:/usr/bin", NULL });
			}
			perror("execve");                          /* 失败才到 */
			_exit(126);
		}
		else if (grandchild > 0) {                   /* 子进程 */
		 // 子进程立即退出，让孙进程成为孤儿进程（真正的后台进程）
			_exit(0);
		}
		else {                                       /* fork 失败 */
			perror("fork");
			_exit(127);
		}
	}
	else if (pid > 0) {                              /* 父进程 */
	 // 等待子进程结束，子进程会立即退出
		int st;
		waitpid(pid, &st, 0);
		return 0;  // 后台进程已启动，返回成功
	}

	return -1;  // fork 失败
}